home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
ETC
/
UNIXCARK
< prev
next >
Wrap
Text File
|
1992-01-14
|
13KB
|
599 lines
/* Original Header from BBC BASIC version.
This program will unpack Spark or arc style archives on the BBC
and Archimedes. To produce an archive that can be unpacked using it
you must set arc or Spark to not use squashing.
Although you can use this on the Archie, a much better solution,
is to use !SparkPlug. If you have an Archie, and would like to make
your own archives and manipulate them in style from the desktop,
you need a copy of Spark. This is obtainable for M-#5.99 from:
David Pilling,
P.O. Box 22,
Thornton Cleveleys,
Blackpool.
FY5 1LR.
You are encouraged to add your own bits to this program and pass it on.
If you do modify it, add your name and details below.
V0.00 20th September 1989 -- David Pilling
V0.01 25th September 1989 -- Philip Colmer
Changed BASIC V usage to BASIC II
V0.02 21st February 1990 -- Philip Colmer
Improved support for DFS
V0.03 22nd April 1991 -- Philip Colmer
Fixed bugs in directory handling
This version, renamed Cark (for want of a better name !) is a port
of Bark to Unix C. You are GREATLY encouraged to improve it...
my knowledge of C is very limited and I suspect that the coding
could be much better ! - Alun.
V0.01 4th June 1991 -- Alun Jones
Ported (messily!) to Unix style C.
V0.02 2nd Dec 1991 -- Andy Duplain (duplain@rtf.bt.co.uk)
Further porting to 4.2BSD (and provision made
for System V). Define either 'BSD' or 'SYSV'
when compiling.
V0.03 17th Dec 1991 -- Andy Duplain (duplain@rtf.bt.co.uk)
Fixed errors in function prototypes for PCC
C compilers.
V0.04 20th Dec 1991 -- Andy Duplain (duplain@rtf.bt.co.uk)
Changed '-t' option output from stderr to stdout.
V0.05 8th Jan 1992 -- Andy Duplain (duplain@rtf.bt.co.uk)
Added patch posted to NEWS by Martin Percival
(martin@thed.uk22.bull.com) to unpack type 127 archives.
*/
#include <stdio.h>
#ifdef BSD /* Berkeley */
# include <strings.h>
# define remove unlink
# define UNIX
# undef SYSV
#endif
#ifdef SYSV /* System V */
# include <sys/types.h>
# include <sys/stat.h>
# include <string.h>
# include <stdlib.h>
# define remove unlink
# define UNIX
# undef BSD
#endif
#ifndef UNIX /* Not UNIX */
# include <string.h>
# include <stdlib.h>
#endif
#define MAXCODE(n) ((1<<n)-1)
/* Used by many functions */
static FILE * fp,
*fo,
*logfile;
static char rmask[9] = {
0, 1, 3, 7, 15, 31, 63, 127, 255
};
static int buf[128];
static char filename[255];
char compname[270]; /* Ready for system() uncompress call */
static int isdir,
earc;
static int run,
c,
rc;
/* permissions of files, lengths, etc. */
static long load,
exec,
attr,
type,
clen,
olen;
static int date,
time,
crc;
/* Used by uncrunch/getcode */
static int n_bits,
clear_flg,
maxcode,
free_ent,
offset,
size;
int testonly = 0; /* Used by -t option */
/* Used to guard function prototypes for PCC and ANSI compilers... */
#if defined(__STDC__) || defined(__cplusplus)
# define P_(s) s
#else
# define P_(s) ()
#endif
int main P_((int argc, char **argv));
int rdhdr P_((void));
long word P_((void));
int dble P_((void));
void unpack P_((char *root, char *file));
void unstore P_((void));
void unpck P_((void));
void putc_ncr P_((int b));
int get_c P_((void));
void uncrunch P_((void));
int getcode P_((void));
#undef P_
int main (argc, argv)
int argc;
char **argv;
{
char cline[256],
fullname[256];
int level = 0;
int l[32];
l[0] = 0;
*fullname = 0;
/* Wrong # args */
if (argc < 2) {
fprintf (stderr, "Usage : %s [-t] <filename>\n", *argv);
exit (1);
}
/* Crappy option parsing... */
if (argc == 3 && argv[1][0] == '-')
{
switch(argv[1][1])
{
case 't': /* Test */
testonly++;
break;
default:
fprintf(stderr, "Unknown option '-%c'\n", argv[1][1]);
exit(1);
}
*++argv;
}
/* Can't open file for reading */
if ((fp = fopen (*++argv, "r")) == NULL) {
fprintf (stderr, "\nCan't find file %s\n", *argv);
exit (1);
}
/* Version number */
puts("Cark V0.05 January 1992, based on Bark V0.03");
/* File types */
if (!testonly)
logfile = fopen ("settypes", "w");
/* Main loop - rdhdr returns non-zero if EOF reached */
while (!rdhdr ()) {
/* End of top level dir */
if ((earc) && (level == 0))
break;
/* New directory in archive */
if (isdir) {
l[level++] = strlen(fullname);/* Remember old pathname */
strcat(fullname, filename);/* Add new name */
if (!testonly)
{
printf("Creating directory %s\n", fullname);
#ifdef UNIX
mkdir(fullname, 0755); /* Ignore error */
#else /* Not UNIX */
sprintf (cline, "mkdir %s\n", fullname);
system (cline);
#endif /* UNIX */
}
else
printf("Directory %s\n", fullname);
strcat (fullname, "/");/* Add the dir. separator */
}
else
if (earc) {
fullname[l[--level]] = 0;/* Step back up a level */
if (strlen (fullname) != 0)
printf ("Directory: %s\n", fullname);
}
else {
if (testonly)
printf ("Testing file : %s%s ... ", fullname, filename);
else
printf ("Restoring file : %s%s ... ", fullname, filename);
unpack (fullname, filename);/* Not a dir, so a file */
}
}
/* End of archive, so close files */
fclose (fp);
if (!testonly)
fclose (logfile);
exit (0);
}
/* Read header */
int rdhdr () {
int i;
/* archive flag */
if (getc (fp) != 26) { /* Missing flag, try and find another */
fprintf (stderr, "Bad Header\n");
while ((i = getc (fp)) != 26)
if (i == EOF)
break;
if (i == EOF) {
return (1);
}
}
/* Compression type */
type = getc (fp) & 0x7f;
if (type == 0) { /* End of archive */
earc = 1;
isdir = 0;
return (0);
}
earc = 0;
for (i = 0; i <= 12; ++i) { /* Get filename */
filename[i] = getc (fp);
if (filename[i] <= 32)
filename[i] = 0;
}
clen = word (); /* Compressed length */
date = dble (); /* File creation date */
time = dble (); /* File creation time */
crc = dble (); /* crc byte - unchecked */
if (type > 1)
olen = word (); /* Compressed, so find original length */
else
olen = clen; /* Not compressed */
load = word (); /* Load address */
exec = word (); /* Execution address */
attr = word (); /* File attributes */
if ((type == 2) && ((load & 0xffffff00) == 0xfffddc00))
isdir = 1; /* File is a directory */
else
isdir = 0; /* No it aint ! */
return (0);
}
/* Get 4 bytes */
long word () {
long n;
n = getc (fp);
n |= (getc (fp) << 8);
n |= (getc (fp) << 16);
n |= (getc (fp) << 24);
return (n);
}
/* Get 2 bytes */
int dble () {
int i;
i = getc (fp);
i |= (getc (fp) << 8);
return (i);
}
/* Unpack file */
void unpack (root, file)
char *root,
*file;
{
char fullpath[255];
int i;
/* Open file and report any error */
sprintf (fullpath, "%s%s", root, file);
if (!testonly && type != 127) /* type 127 uncompressed seperately */
if ((fo = fopen (fullpath, "w")) == NULL) {
fprintf (stderr, "Can't open file %s\n", fullpath);
exit (1);
}
/* Decide appropriate compression action */
switch (type) {
case 1:
case 2:
/* Not compressed */
unstore ();
break;
case 8:
/* Crunched */
uncrunch ();
break;
case 3:
/* I dunno */
unpck ();
break;
case 127: /* Compressed file, save as *.Z and use compress utility */
if (testonly)
puts("unix compress file");
else
puts("Uncompressing");
strcpy(compname, "compress -d "); /* Perferable to uncompress */
strcat(fullpath, ".Z");
strcat(compname, fullpath);
if (!testonly)
{
if ((fo = fopen(fullpath, "w")) == NULL)
{
fprintf(stderr, "Can't open file %s\n", fullpath);
exit(1);
}
putc(31, fo); /* Write magic header for compress file */
putc(157, fo);
putc((getc(fp) + 0x80), fo); /* and adjust byte 1 of file to be UNIX
bit indicator */
while (clen-- > 1)
putc(getc(fp), fo); /* Copy bytes (-1) */
fclose(fo);
if (system(compname)) /* Do the uncompress */
{
fprintf(stderr, "%s failed!\n", compname);
exit(1);
}
}
else /* Testing only */
while(clen--)
getc(fp); /* Throw away */
break;
default:
{
if (!testonly)
fprintf (stderr, "Can't unpack %s - compression type %d\n", file, type);
else
printf("Can't unpack, compression type %d\n", type);
/* Skip to end of file */
for (i = 1; i <= clen; ++i)
getc (fp);
/* Remove output file */
if (!testonly)
remove (fullpath);
}
}
if (!testonly && type != 127)
fclose (fo);
/* Save appropriate SYS "OS_File" call to set catalogue info */
if (!testonly)
{
fprintf (logfile, "SYS %cOS_File%c, 1, %c", 34, 34, 34);
for (i = 0; root[i] != 0; ++i)
if (root[i] == '/')
putc ('.', logfile);
else
putc (root[i], logfile);
fprintf (logfile, "%s%c, &%x, &%x,, &%x\n", file, 34, load, exec, attr);
}
}
/* No compression */
void unstore () {
int i;
putchar('\n');
for (i = 0; i < clen; ++i)
if (testonly)
getc(fp);
else
putc (getc (fp), fo);
}
/* Looks like run length of some sort to me */
void unpck () {
int i;
run = 0;
c = 0;
if (testonly)
putchar('\n');
else
puts("Unpacking");
for (i = 0; i < clen; ++i)
putc_ncr (getc (fp));
}
/* Dunno */
void putc_ncr (b)
int b;
{
int k;
if (testonly)
return;
if (c == 1) {
if (b == 0) {
putc (0x90, fo);
c = 0;
return;
}
else {
for (k = 1; k < b; ++k)
putc (run, fo);
c = 0;
return;
}
}
if (b == 0x90) {
c = 1;
return;
}
run = b;
putc (run, fo);
}
int get_c () {
if (rc > 0) {
--rc;
return (getc (fp));
}
else
return (-1);
}
/* Crunched */
void uncrunch () {
int i,
finchar,
incode,
code,
oldcode;
int stack[4096],
*stackp;
int suffix[4096];
int prefix[4096];
if (testonly)
putchar('\n');
else
puts("Uncrunching");
c = 0;
offset = 0;
size = 0;
rc = clen;
code = get_c ();
if (code != 12) {
fprintf (stderr, "Can't unpack file - wrong number of bits\n");
exit (1);
}
n_bits = 9;
clear_flg = 0;
maxcode = MAXCODE (n_bits);
for (i = 0; i <= 256; ++i)
prefix[i] = 0;
for (code = 0; code < 256; ++code)
suffix[code] = code;
free_ent = 257;
oldcode = getcode ();
finchar = oldcode;
if (oldcode == -1)
return;
putc_ncr (finchar);
stackp = stack;
while (1) {
code = getcode ();
if (code < 0)
return;
if (code == 256) {
for (i = 0; i <= 256; ++i)
prefix[i] = 0;
clear_flg = 1;
free_ent = 256;
code = getcode ();
if (code == -1)
return;
}
incode = code;
if (code >= free_ent) {
*stackp++ = finchar;
code = oldcode;
}
while (code >= 256) {
*stackp++ = suffix[code];
code = prefix[code];
}
finchar = suffix[code];
*stackp++ = finchar;
while (stackp > stack)
putc_ncr (*--stackp);
code = free_ent;
if (code < 4096) {
prefix[code] = oldcode;
suffix[code] = finchar;
free_ent = code + 1;
}
oldcode = incode;
}
}
int getcode () {
int code,
temp,
r_off,
bits;
int bp = 0;
if ((clear_flg > 0) || (offset >= size) || (free_ent > maxcode)) {
if (free_ent > maxcode) {
++n_bits;
if (n_bits == 12)
maxcode = 4096;
else
maxcode = MAXCODE (n_bits);
}
if (clear_flg > 0) {
n_bits = 9;
maxcode = MAXCODE (n_bits);
clear_flg = 0;
}
for (size = 0; size < n_bits; ++size) {
code = get_c ();
if (code == -1) {
temp = size;
size = n_bits;
}
else
buf[size] = code;
}
if (size == (n_bits + 1)) {
size = temp;
if (size <= 0)
return (-1);
}
offset = 0;
size = (size << 3) - (n_bits - 1);
}
r_off = offset;
bits = n_bits;
bp += r_off >> 3;
r_off = r_off & 7;
code = buf[bp++] >> r_off;
bits = bits - 8 + r_off;
r_off = 8 - r_off;
if (bits >= 8) {
code = code | (buf[bp++] << r_off);
r_off += 8;
bits -= 8;
}
code = code | ((buf[bp] & rmask[bits]) << r_off);
offset += n_bits;
return (code & 4095);
}